<template>
  <div class="selectMain">
    <div style="margin: -45px auto; text-algin: center">
      <!-- <button @click="setGame(1)">拖拽模式</button>
      <button @click="setGame(2)">点击有bug模式</button>
      <button @click="setLevel()">选择难度</button> -->
    </div>
    <div id="canvasBox"></div>

    <el-dialog
      title="选择难度等级"
      :visible.sync="dialogVisible"
      width="30%"
      :before-close="handleClose"
    >
      <span>这是一段信息</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleLeve(1)">简单</el-button>
        <el-button type="primary" @click="handleLeve(2)">普通</el-button>
        <el-button type="danger" @click="handleLeve(3)">困难</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import request from '@/utils/request'

export default {
  name: "selectMain",
  data() {
    return {
      msg: "Welcome to Your Vue.js App",
      imgUrl: "../../../static/image/111.jpg",
      //游戏难度
      level: 1,
      dialogVisible: false,
      start:0,
      endGame:0
    };
  },
  methods: {
    handleClose(done) {
    this.$confirm('确认关闭？')
        .then(_ => {
        done();
        })
        .catch(_ => {});
    },
    handleLeve(index){
        this.level=index
        this.dialogVisible=false;
    },
    setLevel(){
        this.dialogVisible=true;
    },
    setGame(index) {
       let that=this;
        this.$confirm('确认开始拼图游戏？')
        .then(_ => {
          that.start=new Date().getTime();
          this.JigsawGame({
              Id: "canvasBox",
              imgUrl: this.imgUrl,
              level: this.level,
              gameType: index,
          });
         done();
        })
        .catch(_ => {});
    },
    JigsawGame(obj) {
      // 初始化容器
      this.Id = document.getElementById(obj.Id);
      let children=this.Id.children;
      while (children.length>0){
            this.Id.removeChild(children[0])
      }
      // 初始化图片
      this.img = new Image();
      this.img.src = obj.imgUrl;
      // 容器最大宽度
      this.windowWidth = document.body.clientWidth;
      //   this.windowWidth = 800;
      this.maxWidth = this.windowWidth > 750 ? 750 : this.windowWidth * 0.9;
      // 设置容器宽高
      this.Id.style.width = this.maxWidth + "px";
      this.Id.style.height = this.maxWidth + "px";
      this.Id.style.left = (this.windowWidth - this.maxWidth) / 2 + "px";
      this.Id.style.top = 50 + "px";
      // 获取容器范围
      this.boxOffsetY = parseFloat(this.Id.style.top);
      this.boxOffsetX = parseFloat(this.Id.style.left);

      // 关卡（简单：1 || 普通：2 || 困难：3）
      if (obj.level == 1 || obj.level == 2 || obj.level == 3) {
        this.Level = obj.level;
      } else {
        this.level = 1;
      }
      // 难度
      let diffArr = [3, 4, 5];
      this.Diff = diffArr[this.Level - 1];
      // canvas宽高
      this.cW = this.maxWidth / this.Diff;
      this.cH = this.maxWidth / this.Diff;
      // 记录的小方块个数
      this.number = 0;
      // 正确的数组
      this.numberArr = [];
      // 存储小方块的中心点坐标
      this.centerXY = [];
      /*
       * 获取游戏类型
       */
      this.gameType = obj.gameType || 1;

      // 记录最后一个元素的标记
      this.lastElement = {
        sign: 0,
        left: 0,
        top: 0,
        Id: obj.Id + 1,
      };
      // 初始化
      this.Init();
    },
    Init() {
      let that = this;
      this.img.onload = function () {
        // 格子宽高
        let LevelW = that.img.width / that.Diff;
        let LevelH = that.img.height / that.Diff;
        for (let i = 0; i < that.Diff; i++) {
          for (let j = 0; j < that.Diff; j++) {
            // 初始化小方块
            that.initCube(i, j, LevelW, LevelH);
          }
        }
        // 打乱小方块
        that.upsetElement();
        // 游戏类型判断
        if (that.gameType == 1) {
          // 监听拖动
          that.Id.addEventListener(
            "mousedown",
            function (event) {
              that.mouseDown(event);
            },
            false
          );
        } else {
          // 获取空白小方块坐标
          that.getLastElement();

          // 监听点击
          that.Id.addEventListener(
            "click",
            function (event) {
              that.mouseClick(event);
            },
            false
          );
        }
      };
    },
    /*
     * @method 初始化小方块
     * @param i Number 循环值
     * @param j Number 循环值
     * @param j LevelW 小方块宽
     * @param j LevelH 小方块高
     */ initCube: function (i, j, LevelW, LevelH) {
      // 创建一个小方块
      let item = document.createElement("div"),
        cW = this.cW,
        cH = this.cH;

      item.className = "item";
      item.setAttribute("data-index", this.number);
      item.style.width = cW + "px";
      item.style.height = cH + "px";
      item.style.left = i * cW + "px";
      item.style.top = j * cH + "px";
      item.innerHTML =
        "<canvas class='' width='" + cW + "' height='" + cH + "'></canvas>";
      this.Id.appendChild(item);

      let canvas = item.querySelector("canvas");
      let ctx = canvas.getContext("2d");

      /*
       * 当游戏为点击类型时
       * 去掉最后一个小方块里的图片
       * 且记录当前元素的坐标以及编号
       */
      if (this.gameType != 1 && j == this.Diff - 1 && i == this.Diff - 1) {
        this.lastElement.sign = this.number;
        item.id = this.lastElement.Id;
      } else {
        ctx.drawImage(
          this.img,
          i * LevelW,
          j * LevelH,
          LevelW,
          LevelH,
          0,
          0,
          cW,
          cH
        );
      }

      // 每添加一个就压入一次到数组
      this.numberArr.push({
        x: i * cW + "px",
        y: j * cH + "px",
      });
      this.number++;

      // 压入初始中心点
      this.centerXY.push({
        x: i * cW + cW / 2,
        y: j * cH + cH / 2,
      });
    },
    /*
     * @method 悬停拖住小方块
     * @param event Object 鼠标对象
     */ mouseDown: function (event) {
      console.log(event);

      let event1 = event || window.event;

      let that = this;

      let target = event1.target || event1.srcElement;

      // 保证拖动的是想要的元素
      if (target.parentElement.className.toLowerCase() == "item") {
        let Element = target.parentElement;

        // 存储当前元素的top,left
        let thisTop = parseFloat(Element.style.top);
        let thisLeft = parseFloat(Element.style.left);

        // 获取当前点击的位置
        let pageX = event1.pageX;
        let pageY = event1.pageY;

        // 拖动
        document.onmousemove = function (e) {
          console.log(e);
          that.mouseMove(e, Element, thisTop, thisLeft, pageY, pageX);

          return false;
        };

        // 松开
        document.onmouseup = function (e) {
          that.mouseUp(e, Element, thisTop, thisLeft);

          // 释放拖拽
          document.onmousemove = null;
          document.onmouseup = null;
          return false;
        };
      }

      return false;
    },
    /*
     * @method 拖动小方块
     * @param e Object 鼠标对象
     */ mouseMove: function (e, Element, thisTop, thisLeft, pageY, pageX) {
      let pageX2 = e.pageX;
      let pageY2 = e.pageY;
      Element.style.top = thisTop + (pageY2 - pageY) + "px";
      Element.style.left = thisLeft + (pageX2 - pageX) + "px";
      Element.style.zIndex = 1000;
    },
    /*
     * @method 松开小方块
     * @param e Object 鼠标对象
     */ mouseUp: function (e, Element, thisTop, thisLeft) {
      let that = this,
        cW = this.cW,
        cH = this.cH;

      // 检测当前拖动替换目标
      let moveCenterX = parseFloat(Element.style.left) + cW / 2;
      let moveCenterY = parseFloat(Element.style.top) + cH / 2;
      let changeElementIndex = this.checkChangeElement(
        moveCenterX,
        moveCenterY
      );
      let changeElement =
        this.Id.getElementsByClassName("item")[changeElementIndex];

      // 限制拖拽范围
      // 当松开的坐标xy在容器范围内
      if (
        e.pageX < this.boxOffsetX ||
        e.pageX > this.boxOffsetX + this.maxWidth ||
        e.pageY < this.boxOffsetY ||
        e.pageY > this.boxOffsetY + this.maxWidth
      ) {
        console.log("释放");

        Element.style.top = thisTop + "px";
        Element.style.left = thisLeft + "px";
      } else {
        // 判断当前元素是否离开了自己的格子
        if (
          Element.getAttribute("data-index") ==
          changeElement.getAttribute("data-index")
        ) {
          Element.style.top = thisTop + "px";
          Element.style.left = thisLeft + "px";
        } else {
          // 进行替换
          Element.style.top = changeElement.style.top;
          Element.style.left = changeElement.style.left;

          changeElement.style.top = thisTop + "px";
          changeElement.style.left = thisLeft + "px";
          changeElement.style.zIndex = 1000;

          // 更新小方块中心点
          this.updateElement();
        }
      }

      // 消除层级问题
      setTimeout(function () {
        Element.style.zIndex = 0;
        changeElement.style.zIndex = 0;
        if (that.compareArray()) {
          that.endGame=new Date().getTime();
          let secends=(that.endGame-that.start)/1000;
          alert("恭喜你，拼图成功！用时："+secends+"秒");
        }
      }, 150);

      // 判断拼图完成
      console.log(this.compareArray());
      console.log(this.numberArr);
    },
    /*
     * @method 检测当前拖动替换目标
     * @param moveLeft Number 鼠标移动的x值
     * @param moveTop Number 鼠标移动的y值
     * @return minIndex Number 返回目标对象下标
     * 通过三角函数检测当前拖动对象中心点和其他所有对象中心点距离，离谁最近就和谁替换
     */ checkChangeElement: function (moveLeft, moveTop) {
      // 最小距离
      let minDistance = null;
      // 最小距离替换目标
      let minIndex = null;

      for (let i = 0; i < this.centerXY.length; i++) {
        let x = Math.abs(moveLeft - this.centerXY[i].x);
        let y = Math.abs(moveTop - this.centerXY[i].y);
        let val = Math.ceil(Math.sqrt(x * x + y * y));

        // 初次判断
        if (minDistance == null) {
          minDistance = val;
          minIndex = i;
        }
        // 后续判断
        if (minDistance > val) {
          minDistance = val;
          minIndex = i;
        }
      }

      // 返回目标对象下标
      return minIndex;
    },
    /*
     * @method 更新小方块中心点
     */
    updateElement: function () {
      let allElement = this.Id.getElementsByClassName("item"),
        cW = this.cW,
        cH = this.cH;
      this.centerXY = [];

      for (let i = 0; i < allElement.length; i++) {
        this.centerXY.push({
          x: parseFloat(allElement[i].style.left) + cW / 2,
          y: parseFloat(allElement[i].style.top) + cH / 2,
        });
      }
    },
    /*
     * @method 点击小方块
     * @param event Object 鼠标对象
     * @ 1、点击当前非空白小方块
     * @ 2、获取其坐标，并加减一个一个方块宽度，用这个加减坐标去检索空白小方块是否在目标小方块周边
     * @ 3、如果在，则替换这两个小方块的坐标
     */ mouseClick: function (event) {
      console.log(event);

      let event2 = event || window.event;

      let that = this;

      let target = event2.target || event2.srcElement;

      // 保证拖动的是想要的元素
      if (target.parentElement.className.toLowerCase() == "item") {
        let Element = target.parentElement;

        // 当当前点击目标为空白小方块时，终止函数
        if (Element.getAttribute("data-index") == this.lastElement.sign) {
          return;
        }

        // 存储当前元素的top,left
        let thisTop = parseFloat(Element.style.top);
        let thisLeft = parseFloat(Element.style.left);

        // 点击检测空白方块是否在当前对象周边
        if (this.mouseClickCheck(thisTop, thisLeft)) {
          console.log(222);
          // 获取空白元素
          let lastElement = document.getElementById(this.lastElement.Id);

          // 替换这两个元素的坐标
          Element.style.top = lastElement.style.top;
          Element.style.left = lastElement.style.left;

          lastElement.style.top = thisTop + "px";
          lastElement.style.left = thisLeft + "px";

          this.lastElement.left = thisLeft;
          this.lastElement.top = thisTop;

          // 消除层级问题
          setTimeout(function () {
            if (that.compareArray()) {
              
              that.endGame=new Date().getTime();
              let secends=(that.endGame-that.start)/1000;
              alert("恭喜你，拼图成功！用时："+secends+"秒");
            }
          }, 150);

          // 判断拼图完成
          console.log(this.compareArray());
          console.log(this.numberArr);
        }
      }

      return false;
    },
    /*
     * @method 点击检测空白方块是否在当前对象周边
     * @param thisTop Number 当前点击元素的top
     * @param thisLeft NUmber 当前点击元素的left
     * @return Boolean 是否在周边
     */ mouseClickCheck: function (thisTop, thisLeft) {
      let cW = this.cW,
        cH = this.cH;
      if (
        thisTop == this.lastElement.top &&
        thisLeft - cH == this.lastElement.left
      ) {
        return true;
      }
      if (
        thisTop == this.lastElement.top &&
        thisLeft + cH == this.lastElement.left
      ) {
        return true;
      }

      if (
        thisTop - cW == this.lastElement.top &&
        thisLeft == this.lastElement.left
      ) {
        return true;
      }

      if (
        thisTop + cW == this.lastElement.top &&
        thisLeft == this.lastElement.left
      ) {
        return true;
      }

      return false;
    },
    /*
     * @method 获取空白元素left,right
     */ getLastElement: function () {
      // 获取空白元素
      let lastElement = document.getElementById(this.lastElement.Id);
      console.log(this.lastElement);
      this.lastElement.left = parseFloat(lastElement.style.left);
      this.lastElement.top = parseFloat(lastElement.style.top);
    },

    /*
     * @method 打乱小方块
     * 以小方块的个数为次数，每次随机抽取两个小于小方块的数，然后替换两个dom元素的定位坐标
     */
    upsetElement: function () {
      for (let i = 0; i < this.number - 1; i++) {
        // 获取两个不相等的随机值
        let n1 = Math.floor(Math.random() * this.number);
        let n2 = Math.floor(Math.random() * this.number);
        do {
          n2 = Math.floor(Math.random() * this.number);
        } while (n1 == n2);

        // 替换当前的两个小方块的坐标
        let allElement = this.Id.getElementsByClassName("item");
        let Top = allElement[n1].style.top;
        let Left = allElement[n1].style.left;

        allElement[n1].style.top = allElement[n2].style.top;
        allElement[n1].style.left = allElement[n2].style.left;

        allElement[n2].style.top = Top;
        allElement[n2].style.left = Left;
      }
    },

    /*
     * @method 比较小方块是否拼图完成
     * @return boolean
     * 获取切换小方块后，获取小方块的序号并与正确排序数组进行比较
     */
    compareArray: function () {
      // 获取序号
      let allElement = this.Id.getElementsByClassName("item");

      for (let i = 0; i < this.number - 1; i++) {
        // 比较序号
        if (
          this.numberArr[i].x != allElement[i].style.left ||
          this.numberArr[i].y != allElement[i].style.top
        ) {
          return false;
        }
      }

      return true;
    },
    getImage(value){
      let that = this;
      let data=request({
        url: '/pingtu/exist-user',
        method: 'post',
        data:{"name":value}
      })
      Promise.all([data]).
      then(res => {
        let data=res[0];
        if(data.code==200){
          that.imgUrl=data.data;
          that.setGame(2);
        }
      });
    }
  },
  mounted() {
    let value = this.$route.query.name;
    this.getImage(value);
  },
};
</script>

<style>
#canvasBox {
  margin: 0 auto;
  position: fixed;
  border: 2px solid #f00;
  overflow: hidden;
}
.item {
  display: inline-block;
  border: 1px solid #f00;
  position: absolute;
  top: 0;
  left: 0;
  transition: 0.1s;
}
</style>
